﻿// Copyright (c) Ubisoft. All Rights Reserved.
// Licensed under the Apache 2.0 License. See LICENSE.md in the project root for license information.

using System.Collections.Generic;
using System.IO;

namespace Sharpmake.Generators.VisualStudio
{
    public abstract class UserFileBase
    {
        protected const string RemoveLineTag = FileGeneratorUtilities.RemoveLineTag;
        protected const string UserFileExtension = ".user";

        private readonly string _userFilePath;

        /// <summary>
        /// Base class for generating VS user files.
        /// </summary>
        /// <param name="projectFilePath">
        /// Path to the project file. The suffix ".user" will be appended to the file name.
        /// </param>
        protected UserFileBase(string projectFilePath)
        {
            _userFilePath = projectFilePath + UserFileExtension;
        }

        protected abstract void GenerateConfigurationContent(IFileGenerator fileGenerator, Project.Configuration conf);

        protected abstract bool HasContentForConfiguration(Project.Configuration conf, out bool overwrite);

        // Generate the user file. The base class is responsible for generating the file header and footer.
        // Actual user content is generated by the specialized user file class.
        public void GenerateUserFile(Builder builder, Project project, IEnumerable<Project.Configuration> configurations, IList<string> generatedFiles, IList<string> skipFiles)
        {
            var fileGenerator = new FileGenerator();
            bool needToWriteFile = false;
            bool overwriteFile = true;

            foreach (Project.Configuration conf in configurations)
            {
                bool overwriteFileConfig;
                if (HasContentForConfiguration(conf, out overwriteFileConfig))
                {
                    if (!needToWriteFile)
                    {
                        fileGenerator.WriteLine(Template.UserFileHeader);
                        needToWriteFile = true;
                    }
                    overwriteFile &= overwriteFileConfig;

                    using (fileGenerator.Declare("platformName", Util.GetToolchainPlatformString(conf.Platform, conf.Project, conf.Target)))
                    using (fileGenerator.Declare("conf", conf))
                    using (fileGenerator.Declare("project", project))
                    {
                        fileGenerator.WriteLine(Template.PropertyGroupHeader);
                        GenerateConfigurationContent(fileGenerator, conf);
                        fileGenerator.WriteLine(Template.PropertyGroupFooter);
                    }
                }
            }

            if (needToWriteFile)
            {
                fileGenerator.WriteLine(Template.UserFileFooter);

                // remove all line that contain RemoveLineTag
                fileGenerator.RemoveTaggedLines();
                FileInfo userFileInfo = new FileInfo(_userFilePath);
                //Skip overwriting user file if it exists already so he can keep his setup
                // unless the UserProjSettings specifies to overwrite
                bool shouldWrite = !userFileInfo.Exists || overwriteFile;
                if (shouldWrite && builder.Context.WriteGeneratedFile(project.GetType(), userFileInfo, fileGenerator))
                {
                    generatedFiles.Add(userFileInfo.FullName);
                }
                else
                {
                    // prevent deletion of skipped files.
                    Util.RecordInAutoCleanupDatabase(userFileInfo.FullName);
                    skipFiles.Add(userFileInfo.FullName);
                }
            }
        }

        public static class Template
        {
            public static readonly string UserFileHeader =
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">";

            public static readonly string UserFileFooter = @"</Project>";

            public static readonly string PropertyGroupHeader =
                @"  <PropertyGroup Condition=""'$(Configuration)|$(Platform)'=='[conf.Name]|[platformName]'"">";

            public static readonly string PropertyGroupFooter = @"  </PropertyGroup>";
        }
    }
}
